package com.roadjava.rbac.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.roadjava.rbac.bean.entity.AuthorityDO;
import com.roadjava.rbac.bean.req.authority.AuthorityAddReq;
import com.roadjava.rbac.bean.req.authority.AuthorityUpdateReq;
import com.roadjava.rbac.bean.vo.AuthorityTreeVO;
import com.roadjava.rbac.bean.vo.AuthorityVO;
import com.roadjava.rbac.constants.CommonConstants;
import com.roadjava.rbac.enums.AuthorityTypeEnum;
import com.roadjava.rbac.enums.YesNoEnum;
import com.roadjava.rbac.ex.BizEx;
import com.roadjava.rbac.service.AuthorityService;
import com.roadjava.rbac.mapper.AuthorityMapper;
import com.roadjava.rbac.service.LinkRoleAuthorityService;
import com.roadjava.rbac.util.ConvertUtil;
import com.roadjava.rbac.util.SortableTreeUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.condition.PathPatternsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.util.pattern.PathPattern;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

import static cn.hutool.extra.validation.ValidationUtil.validate;
import static org.yaml.snakeyaml.nodes.NodeId.mapping;

/**
* @author 27249
* @description 针对表【authority(权限表)】的数据库操作Service实现
* @createDate 2024-11-01 21:13:03
*/
@Service
public class AuthorityServiceImpl extends ServiceImpl<AuthorityMapper, AuthorityDO>
    implements AuthorityService{
    @Resource
    private RequestMappingHandlerMapping mapping;
    @Resource
    private LinkRoleAuthorityService linkRoleAuthorityService;
    @Override
    public List<AuthorityTreeVO> queryTree() {
        List<AuthorityDO> list = list();
        if (CollUtil.isEmpty(list)) {
            return Collections.emptyList();
        }
        List<AuthorityTreeVO> nodeList = list.stream()
                .map(authority -> {
                    // 同名属性赋值
                    AuthorityTreeVO vo = ConvertUtil.convert(authority,AuthorityTreeVO.class);
                    vo.setValue(authority.getId());
                    vo.setLabel(authority.getAuthorityName());
                    return vo;
                }).collect(Collectors.toList());
        return SortableTreeUtil.buildTree(nodeList);
    }

    @Override
    public List<String> listBackUri() {
        List<String> retList = new ArrayList<>();
        // RequestMappingInfo包含了请求映射信息
        Map<RequestMappingInfo, HandlerMethod> handlerMethods = mapping.getHandlerMethods();
        for (RequestMappingInfo requestMappingInfo : handlerMethods.keySet()) {
            PathPatternsRequestCondition condition = requestMappingInfo.getPathPatternsCondition();
            if (condition == null) {
                continue;
            }
            // 获取到映射uri列表,因为一个方法可以有多个映射uri
            Set<PathPattern> patterns = condition.getPatterns();
            if (CollUtil.isEmpty(patterns)) {
                continue;
            }
            retList.addAll(patterns.stream().map(PathPattern::getPatternString).collect(Collectors.toList()));
        }
        // distinct restful风格的情况
        return retList.stream().distinct().sorted().collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(AuthorityAddReq addReq) {
        AuthorityDO entity = ConvertUtil.convert(addReq, AuthorityDO.class);
        // 把list转成,分隔的字符串
        entity.setRelateBackUris(CollUtil.join(addReq.getRelateBackUriList(), CommonConstants.COMMA));
        validate(entity);
        save(entity);
    }

    @Override
    public List<AuthorityVO> queryTableTree() {
        List<AuthorityDO> list = list();
        if (CollUtil.isEmpty(list)) {
            return Collections.emptyList();
        }
        List<AuthorityVO> vos = ConvertUtil.convert(list, AuthorityVO.class);
        return SortableTreeUtil.buildTree(vos);
    }

    @Override
    public AuthorityVO queryById(Long id) {
        AuthorityDO entity = getById(id);
        return ConvertUtil.convert(entity,AuthorityVO.class);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void modifyById(AuthorityUpdateReq updateReq) {
        AuthorityDO entity = ConvertUtil.convert(updateReq, AuthorityDO.class);
        // 把list转成,分隔的字符串
        entity.setRelateBackUris(CollUtil.join(updateReq.getRelateBackUriList(), CommonConstants.COMMA));
        validate(entity);
        updateById(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteById(Long id) {
        // 首先检查要删除的权限是否存在
        AuthorityDO authority = getById(id);
        if (authority == null) {
            // 如果没有找到该权限，抛出自定义异常
            throw new NoDataFoundException("权限 ID " + id + " 不存在，无法删除。");
        }

        // 查询是否有子级（如果需要删除子级，则保留这一部分）
        LambdaQueryWrapper<AuthorityDO> lqw = new LambdaQueryWrapper<>();
        lqw.eq(AuthorityDO::getParentId, id);
        List<AuthorityDO> children = list(lqw);
        if (CollUtil.isNotEmpty(children)) {
            // 如果有子级，递归删除子级
            children.forEach(child -> deleteById(child.getId()));
        }

        // 删除关联表中的数据
        linkRoleAuthorityService.deleteByAuthorityId(id);
        // 删除当前权限
        removeById(id);
    }

    // 自定义异常类
    public class NoDataFoundException extends RuntimeException {
        public NoDataFoundException(String message) {
            super(message);
        }
    }

    private void validate(AuthorityDO entity) {
        if (AuthorityTypeEnum.ROUTE_COMPONENT.getCode().equals(entity.getType())) {
            if (StrUtil.isBlank(entity.getPath())) {
                throw new BizEx("路由组件的路由路径不能为空");
            }
            if (StrUtil.isBlank(entity.getComponentPath())) {
                throw new BizEx("路由组件的组件路径不能为空");
            }
        }else {
            // 按钮的情况
            entity.setShowInMenu(YesNoEnum.N.getCode());
            entity.setIcon(null);
            entity.setPath(null);
            entity.setComponentPath(null);
        }
    }
}




